#include "stdio.h"
#include"arm.h"
#include"cpu.h"

#ifndef __GNUC__
#pragma warning(disable : 4700)
#endif


bool CCPU::exec_arm_fmt10()
{
	__u32 start_address;
	__u32 end_address;
	__u32 final_Rn;
	__u32 Number_Of_Set_Bits;



	Number_Of_Set_Bits=0;
	for(int i=0;i<16;i++) 
		if(arm_insn.insn_fmt10.reg_list&(1<<i)) 
			Number_Of_Set_Bits++;

	switch(arm_insn.insn_fmt10a.addr_mode)
	{
        case ADDR_MODE_DA:
		//start_address = Rn - (Number_Of_Set_Bits_In(register_list) * 4) + 4
		//end_address = Rn
		//if ConditionPassed(cond) and W == 1 then
		//Rn = Rn - (Number_Of_Set_Bits_In(register_list) * 4)
		final_Rn=regfile.read_register(arm_insn.insn_fmt10a.Rn)-Number_Of_Set_Bits*4;
        start_address=final_Rn+4;
        end_address=regfile.read_register(arm_insn.insn_fmt10a.Rn);
        break;
        case ADDR_MODE_IA:
		//start_address = Rn
		//end_address = Rn + (Number_Of_Set_Bits_In(register_list) * 4) - 4
		//if ConditionPassed(cond) and W == 1 then
		//Rn = Rn + (Number_Of_Set_Bits_In(register_list) * 4)
        final_Rn=regfile.read_register(arm_insn.insn_fmt10a.Rn)+Number_Of_Set_Bits*4;
        start_address=regfile.read_register(arm_insn.insn_fmt10a.Rn);
        end_address=final_Rn-4;
        break;
        case ADDR_MODE_DB:
		//start_address = Rn - (Number_Of_Set_Bits_In(register_list) * 4)
		//end_address = Rn - 4
		//if ConditionPassed(cond) and W == 1 then
		//Rn = Rn - (Number_Of_Set_Bits_In(register_list) * 4)
        start_address=regfile.read_register(arm_insn.insn_fmt10a.Rn)-Number_Of_Set_Bits*4;
        end_address=regfile.read_register(arm_insn.insn_fmt10a.Rn)-4;
		final_Rn=start_address;
        break;
        case ADDR_MODE_IB:
		//start_address = Rn + 4
		//end_address = Rn + (Number_Of_Set_Bits_In(register_list) * 4)
		//if ConditionPassed(cond) and W == 1 then
		//Rn = Rn + (Number_Of_Set_Bits_In(register_list) * 4)
        start_address=regfile.read_register(arm_insn.insn_fmt10a.Rn)+4;
        end_address=regfile.read_register(arm_insn.insn_fmt10a.Rn)+Number_Of_Set_Bits*4;
		final_Rn=end_address;
        break;
	}

	//
	// ldm or stm
	//
	if(!arm_insn.insn_fmt10a.L)
	{
		__u32 address=start_address;
		for(int i=0;i<16;i++) 
			if(arm_insn.insn_fmt10.reg_list&(1<<i)) 
			{
				__u32 dat=regfile.read_register(i);
				if(!write_int(address,dat)) return false;
				//printf("stm:%x,%x,%d\n",address,dat,i);
				address+=4;
			}
	}
	else
	{
		__u32 dat[16];

		__u32 address=start_address;
		for(int i=0;i<16;i++) 
			if(arm_insn.insn_fmt10.reg_list&(1<<i)) 
			{
				if(!read_int(address,&dat[i])) return false;
				address+=4;
			}
		
		//  LDM 1 or 3
		if((arm_insn.code&0x708000)!=0x500000)
		{
			for(int i=0;i<16;i++) 
				if(arm_insn.insn_fmt10.reg_list&(1<<i)) 
				{
					//printf("ldm:%x,%x,%d\n",address,dat,i);
					regfile.write_register(i,dat[i]);

			}
		}
		// LDM 2 
		else
		{
			for(int i=0;i<16;i++) 
				if(arm_insn.insn_fmt10.reg_list&(1<<i)) 
				{
					//printf("ldm:%x,%x,%d\n",address,dat,i);
					regfile.prf[PREG(i,MODE_USER)]=dat[i];
				}
		}
		//
		// LDM(3)
		//
		//if CurrentModeHasSPSR() then
		//CPSR = SPSR
		//else
		//UNPREDICTABLE
		if((arm_insn.code&0x708000)==0x508000)
		{
			if (CurrentModeHasSPSR())
			{
				regfile.set_cpsr(regfile.prf[Bank_SPSR(regfile.mode)]);
			}
			else
				;//UNPREDICTABLE
		}
	}

	//
	// !
	//
	if(arm_insn.insn_fmt10a.W)
	{
		regfile.write_register(arm_insn.insn_fmt10a.Rn,final_Rn);

	}


	return true;
}